﻿using LayoutHelpers.BaseTypes;
using LayoutHelpers.Primitives;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using Windows.Foundation;
using Windows.UI.Xaml.Markup;

namespace LayoutHelpers.Primitives
{
  [ContentProperty(Name = "Rules")]
  public class LayoutRuleGroup : ILayoutRule, ICommand, ILayoutEvaluator
  {
    public List<ILayoutRule> Rules { get; set; }
    public RuleGroupType ExecutionType { get; set; }
    public string DisplayName { get; set; }

    public LayoutRuleGroup()
    {
      Rules = new List<ILayoutRule>();
      InternalLayoutEvaluator = new DefaultLayoutEvaluator();
      ExecutionType = RuleGroupType.AllMatches;
    }

    public ILayoutEvaluator InternalLayoutEvaluator { get; set; }

    public ILayoutEvaluator LayoutEvaluator
    {
      get { return this; }
    }

    public ICommand Command
    {
      get { return this; }
    }

    public bool CanExecute(object parameter)
    {
      return Rules.Any(r => { r.LayoutEvaluator.Evaluate(lastAvailableSize); return r.Command.CanExecute(parameter); });
    }

    protected void RaiseCanExecuteChanged()
    {
      var handler = CanExecuteChanged;
      if (handler != null)
        CanExecuteChanged(this, EventArgs.Empty);
    }
    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
      foreach (var rule in Rules)
      {
        var result = rule.LayoutEvaluator.Evaluate(lastAvailableSize);
        if (result && rule.Command.CanExecute(parameter))
        {
          rule.Command.Execute(parameter);
          if (ExecutionType == RuleGroupType.FirstMatch)
            return;
        }
      }
    }

    Size lastAvailableSize;
    public bool Evaluate(Size availableSize)
    {
      lastAvailableSize = availableSize;
      if (InternalLayoutEvaluator != null)
        return InternalLayoutEvaluator.Evaluate(availableSize);

      return true;
    }
  }

  [ContentProperty(Name = "LayoutEvaluator")]
  public class SimpleRule : ILayoutRule, ICommand, ILayoutEvaluator
  {
    public ILayoutEvaluator LayoutEvaluator { get; set; }
    virtual public ICommand TrueCommand { get; set; }
    virtual public ICommand FalseCommand { get; set; }
    public string DisplayName { get; set; }

    ILayoutEvaluator ILayoutRule.LayoutEvaluator
    {
      get { return this; }
    }

    ICommand ILayoutRule.Command
    {
      get { return this; }
    }

    bool? lastEvaluateResult;
    public bool Evaluate(Size availableSize)
    {
      if (TrueCommand == null && FalseCommand == null)
      {
        lastEvaluateResult = null;
        return false;
      }

      lastEvaluateResult = LayoutEvaluator.Evaluate(availableSize);

      if (TrueCommand != null)
      {
        if (FalseCommand != null)
          return true;
        else
          return lastEvaluateResult.Value;
      }
      else if (FalseCommand != null)
      {
        return !lastEvaluateResult.Value;
      }

      return false;
    }

    public bool CanExecute(object parameter)
    {
      if (lastEvaluateResult == null)
        return false;
      else if (lastEvaluateResult == true && TrueCommand != null)
        return TrueCommand.CanExecute(parameter);
      else if (FalseCommand != null)
        return FalseCommand.CanExecute(parameter);

      return false;
    }

    protected void RaiseCanExecuteChanged()
    {
      var handler = CanExecuteChanged;
      if (handler != null)
        CanExecuteChanged(this, EventArgs.Empty);
    }
    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
      if (lastEvaluateResult == null)
        return;
      else if (lastEvaluateResult == true && TrueCommand != null)
        TrueCommand.Execute(parameter);
      else if (FalseCommand != null)
        FalseCommand.Execute(parameter);
    }
  }

  public class DefaultVisualStateRule : GoToVisualStateRuleBase<DefaultLayoutEvaluator>
  {
  }

  public class AssertVisualStateRule : GoToVisualStateRuleBase<AssertLayoutEvaluator>
  {
    public string Message
    {
      get { return LayoutEvaluator.Message; }
      set { LayoutEvaluator.Message = value; }
    }

    public AssertVisualStateRule()
    {
      VisualStateName = "Error";
    }
  }
}